//shellFunctions.c

//includes
#include "shellFunctions.h"
#include "linkedList.h"


int child_pgid;
//was aiming for cleanileness here
LIST * parseInput(char *input,int *shellFlags, int *options){
  TOKENIZER *tokenizer;
  LIST *progList;
  LIST *wordList;
  char* tok;
  char** child_argv;
  int i;
  char* filename;
  int new_stdout;
  int new_stdin;
  int shellArgsOnly=0;
  int firstredin=1;
  
  
  //int array of 4 flags
  //shellFlags;
  /* store flags that indicate shell commands 
     option is used to supplement this
     
    | 0 | 1  | 2  |  4    |  5 | 6 | 7 | 
      &   fg   bg   jobs     >   <   |
  */
  /*options:
    |  0  |  1  |   2    | 
      >fd   <fd   jobs #   
   */
  
  //init
  for(i=0;i<8;i++){
    shellFlags[i]=0;
  }


  //init tokenizer
  tokenizer = init_tokenizer(input);
  //init lists
  progList=createList();//for programs (list of argv arrays)
  wordList=createList();//for words (used temp to populate other list)
  
  tok = get_next_token( tokenizer );
  //check for empty input
  if(tok==NULL){
    return NULL;
  }
  //Loop through input and handle shell commands and args
  for(i=0; tok!=NULL; i++,tok = get_next_token( tokenizer )) {
    
    //check redirection, will do file open/dub here
    //looking at tokenizer code, it seems safe to assume that shell args will always be 0 index of token strings (length==1, null terminated)
    if(tok[0]=='>'){
      if(shellFlags[REDOUT]){
	perror(rdrctError);
	return NULL;
      }
   
      // get filename, which will be next token
      if((filename=get_next_token(tokenizer))==NULL){
	perror(rdrctError);
	return NULL;
      }
      //open or create file descriptor
      if((new_stdout=open(filename,O_WRONLY | O_CREAT,S_IRWXU))==-1){perror(openError);return NULL;}
      options[OUTFD]=new_stdout;
    shellFlags[REDOUT]=1;
    
      //stop accepting program args
      //only accept shell args, ie. < > | &
      shellArgsOnly=1;
    }

  //similar case for other direction
    else if(tok[0]=='<'){
     
      if(shellFlags[REDIN] || (shellFlags[PIPE] && !firstredin) ){
	perror(rdrctError);
	return NULL;
      }
      firstredin=0;
      //reusing filename
      filename=get_next_token(tokenizer);
      if((new_stdin=open(filename,O_RDONLY))==-1){perror(openError);return NULL;}
            
      shellFlags[REDIN]=1;
      options[INFD]=new_stdin;
      shellArgsOnly=1;
    }

  //check for pipe
    else if(tok[0]=='|'){
      if (shellFlags[REDOUT]){
	perror(rdrctError);
	return NULL;
      }
      child_argv=(char**)getArray(wordList);
      addEl(progList,child_argv);
      shellFlags[PIPE]=1;
      shellArgsOnly=0;
    }
  //check for amp
    else if(tok[0]=='&'){
      //error if not at end
      if ((tok=get_next_token(tokenizer))!=NULL){
	perror(ampError);
	return NULL;
      }
      shellFlags[RUNBG]=1;
      break;
    }
    //check for fg
    else if(strEquals(tok,"fg")){
      shellFlags[FG]=1;
      tok=get_next_token(tokenizer);
      if (tok==NULL)
	break;
      options[2]=atoi(tok);
    }
    else if(strEquals(tok,"bg")){
      shellFlags[BG]=1;
      tok=get_next_token(tokenizer);
      if (tok==NULL)
	break;
      options[2]=atoi(tok);
    }
    else if(strEquals(tok,"jobs")){
      shellFlags[JOBS]=1;
      
      break;
    }
    else if(strEquals(tok,"exit")){
      _exit(EXIT_SUCCESS);
    }
    else if(shellArgsOnly){
      //if we got here, then there were more tokens that were not > < | &
      //lets error in this situation
      perror(shellArgError);
      return NULL;
    }
    else
      //add this tok to word linked list
      addEl(wordList,tok);

    //lets not free tokens just yet
  }
//lets not forget last one!
  child_argv=(char**)getArray(wordList);
addEl(progList,child_argv);

//free memory
  free_tokenizer( tokenizer ); 
//lists are freed in getArray function

  return progList;
}

void printStringArray(char **array, char delimiter){
  int i;
  for(i=0;array[i]!=NULL;i++) {
    printf("%s%c",array[i],delimiter);
  }
}

int strEquals(char* string1, char* string2){
  int i;
  
  while(1){
    //loop till shortest string ends
    if (string1[i]=='\0' || string2[i]=='\0')
      break;
    //return false on difference
    if (string1[i]!=string2[i]){
      return 0;
    }
    i++;
  }
  //if we got here, and both strings ='\0'
  //we have a match
  if (string1[i]==string2[i])
    return 1;

  //shouldnt get here, for compiler
  return 0;
}
